package com.hzy.es.service;

import com.alibaba.fastjson.JSONObject;
import com.hzy.es.Item;
import org.elasticsearch.action.search.ClearScrollRequest;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchScrollRequestBuilder;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Service;
import sun.reflect.misc.FieldUtil;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.*;

@Service
public class ESScrollService {
    @Resource
    private TransportClient client;

    public List<Item> getAllList() throws Exception {
        List<Item> all = new ArrayList();
        String scrollId = getScrollId("index", "", 2000, "", Item.class, all);

        List<Item> result;
        while (true){
            result = new ArrayList<>();
            // 必须传递前一次请 求返回的scroll_id
            scrollId = getByScrollId(scrollId, result);
            all.addAll(result);
            // 退出
            if (null == result || result.size() < 2000){
                // 清空
                ClearScrollRequest request = new ClearScrollRequest();
                request.setScrollIds(Arrays.asList(scrollId));
                client.clearScroll(request);
                break;
            }
        }
        return all;
    }

    /**
     * 获取 scrollId
     * @param index
     * @param query
     * @param page_size
     * @param order_by
     * @param clz
     * @param list
     * @return
     * @throws Exception
     */
    public String getScrollId(String index,String query,Integer page_size,String order_by,Class clz,
                              List<Item> list) throws Exception {
        // 过滤参数
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        // 滚动查询初始化
        SearchRequestBuilder searchRequestBuilder = generateSearchResponse(index,boolQueryBuilder,page_size,order_by,clz);
        // 获取值
        SearchResponse searchResponse = searchRequestBuilder.setScroll(new TimeValue(120000)).get();
        // scrollId
        String scrollId = searchResponse.getScrollId();
        // 第一批数据
        SearchHits hits = searchResponse.getHits();
        for(int i = 0;i < hits.getHits().length; i++){
            Item skuIndexEntity = JSONObject.parseObject(hits.getHits()[i].getSourceAsString(), Item.class);
            list.add(skuIndexEntity);
        }
        return scrollId;
    }

    /**
     * 滚动查询初始化
     * @param index
     * @param queryBuilder
     * @param page_size
     * @param order_by
     * @param clz
     * @return
     * @throws Exception
     */
    public SearchRequestBuilder generateSearchResponse(String index, QueryBuilder queryBuilder, Integer page_size, String order_by, Class clz) throws Exception {
        // 滚动查询参数定义
        SearchRequestBuilder builder = client.prepareSearch(index)
                .setScroll(new TimeValue(120000))
                .setSize(page_size)
                .setQuery(queryBuilder)
                ;
        // 排序
        Map<String, SortOrder> map =  this.getSort(order_by,clz);
        for (Map.Entry<String, SortOrder> ssEntry : map.entrySet()) {
            builder.addSort(ssEntry.getKey(),ssEntry.getValue());
        }
        return builder;
    }

    /**
     * 排序
     * @param order_by
     * @param clz
     * @return
     * @throws Exception
     */
    public Map<String,SortOrder> getSort(String order_by,Class clz) throws Exception {
        Map<String,SortOrder> ordersMap = new HashMap();
        if(order_by != null && order_by.trim().length() > 1){
            String[] orders = order_by.split(",");
            for (String order : orders) {
                String [] par = order.split(" ");
                if("desc".equals(par[1].toLowerCase())){
                    Field field = FieldUtil.getField(clz, par[0]);
                    if(field == null){
                        throw new Exception(String.format("排序参数{%s}异常,请检查",par[0]));
                    }
                    if("java.lang.String".equals(field.getType().getTypeName())){
                        ordersMap.put(par[0] + ".keyword",SortOrder.DESC);
                    }else{
                        ordersMap.put(par[0],SortOrder.DESC);
                    }

                }else if("asc".equals(par[1].toLowerCase())){
                    Field field = FieldUtil.getField(clz, par[0]);

                    if(field == null){
                        throw new Exception(String.format("排序参数{%s}异常,请检查",par[0]));
                    }
                    if("java.lang.String".equals(field.getType().getTypeName())){
                        ordersMap.put(par[0] + ".keyword",SortOrder.ASC);
                    }else{
                        ordersMap.put(par[0],SortOrder.ASC);
                    }
                }
            }
        }else{
            ordersMap.put(FieldSortBuilder.DOC_FIELD_NAME,SortOrder.ASC);
        }
        return ordersMap;
    }

    /**
     * 根据scrollId查询
     * @param scrollId
     * @return
     */
    public String getByScrollId(String scrollId, List<Item> list){
        SearchScrollRequestBuilder searchScrollRequestBuilder = client.prepareSearchScroll(scrollId);
        // 查询
        SearchResponse searchResponse = searchScrollRequestBuilder.setScroll(new TimeValue(120000)).get();
        // 遍历集合
        SearchHits hits = searchResponse.getHits();
        for(int i = 0;i < hits.getHits().length; i++){
            Item item = JSONObject.parseObject(hits.getHits()[i].getSourceAsString(),Item.class);
            list.add(item);
        }
        return searchResponse.getScrollId();
    }
}
